/***************************************************************************
 * Copyright (C) 2023-, openlinyou, <linyouhappy@outlook.com>
 *
 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
 * copies of the Software, and permit persons to whom the Software is
 * furnished to do so, under the terms of the COPYING file.
 ***************************************************************************/

#ifndef HEADER_OPEN_HTTPS_H
#define HEADER_OPEN_HTTPS_H

#include <assert.h>
#include <memory>
#include <string.h>
#include <map>
#include <vector>
#include "opentime.h"
#include "openbuffer.h"
#include "openfile.h"

namespace open
{

////////////OpenHttp//////////////////////
struct OpenHttp
{
    int code_;
    int64_t clen_;
    bool isReq_;
    bool isHttps_;
    bool isChunked_;
    bool isClient_;
    bool isRemote_;
    bool isFinish_;
    std::string domain_;
    unsigned int port_;
    std::string method_;
    std::string path_;
    std::string host_;
    std::string url_;
    OpenBuffer head_;
    OpenBuffer body_;
    OpenBuffer buffer_;
    std::map<std::string, std::string> params_;
    std::map<std::string, std::string> headers_;

    const std::string& lookIp();
    inline const std::string& ip() { return ip_; }
    inline void setIp(const std::string& ip) { ip_ = ip; }

    inline void getHead(std::string& head) { head.append((const char*)head_.data(), head_.size()); }
    inline void getBody(std::string& body) { body.append((const char*)body_.data(), body_.size()); }
    inline std::string& setParam(const std::string& key) { return params_[key]; }
    std::string& header(const std::string& key);
    bool hasHeader(const std::string& key);
    void removeHeader(const std::string& key);
    inline std::string& operator[](const std::string& key) { return header(key); }

    OpenHttp();
    void parseUrl();
    void encodeReqHeader();
    void encodeRespHeader();
    virtual void decodeReqHeader();
    void decodeRespHeader();
    bool responseData(const char* data, size_t size);
    bool requestData(const char* data, size_t size);
    inline void operator=(const std::string& url) { url_ = url; }

    //bool send(void* data, size_t size);
    void clear()
    {
        code_ = -1;
        clen_ = 0;
        params_.clear();
        head_.clear();
        body_.clear();
        buffer_.clear();
    }

private:
    std::string ip_;
};

////////////OpenHttpResponse//////////////////////
struct OpenHttpResponse : public OpenHttp
{
    std::vector<std::string> paths_;

    OpenHttpResponse() : OpenHttp() { isReq_ = false; }
    virtual void decodeReqHeader();
    void init()
    {
        port_ = 80;
        headers_["server"] = "openlinyou/1.0";
        //headers_["x-power"] = "https://github.com/openlinyou";
        headers_["accept-ranges"] = "bytes";

        OpenTime openTime;
        headers_["date"] = openTime.toGMT();
        //headers_["connection"] = "keep-alive";
        headers_["connection"] = "close";
    }
    void response(const char* ctype, const char* buffer, size_t len)
    {
        code_ = 200;
        body_.pushBack(buffer, len);
        headers_["content-type"] = GetContentType(ctype);
    }
    void response(const char* ctype, const std::string& buffer)
    {
        code_ = 200;
        body_.pushBack(buffer);
        headers_["content-type"] = GetContentType(ctype);
    }
    void response404Html()
    {
        response(".html", "<html><body><h1>404</h1><p>Sorry, We can't provide this service! By OpenLinyou</p></body></html>");
    }
    static const std::string GetContentType(const char* fileExt)
    {
        auto iter = ContentTypes_.find(fileExt);
        if (iter != ContentTypes_.end())
        {
            return iter->second;
        }
        return fileExt;
    }
private:
    static const std::map<std::string, std::string> ContentTypes_;
};

////////////OpenHttpRequest//////////////////////
class OpenHttpRequest : public OpenHttp
{
public:
    OpenHttpRequest(bool isClient = true) : OpenHttp(), listenPort_(0) { isReq_ = true; if (isClient) init(); }
    OpenHttpResponse response_;
    void init()
    {
        port_ = 80;
        headers_["accept"] = "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng";
        headers_["user-agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36(KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36";
        headers_["cache-control"] = "max-age=0";
        //headers_["accept-encoding"] = "gzip,deflate";
        headers_["accept-language"] = "en-us,zh;q=0.9";
        headers_["connection"] = "close";
    }
    int listenPort_;
};

typedef void (*OpenHttpHandle)(OpenHttpRequest&, OpenHttpResponse&);

};


#endif //HEADER_OPEN_HTTPS_H
